﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using ManyinEngine;

namespace TestViewer
{
    public partial class Main : Form
    {
        #region [LOCALS]
        private Graph _graph;
        private List<Tile> _lsTiles;
        private int?[] _selectedNodes;
        #endregion

        public Main()
        {
            _graph = new Graph();
            _selectedNodes = new int?[7];
            _lsTiles = new List<Tile>();

            InitializeComponent();
            LoadEdges();
            BindingList<Node> source = new BindingList<Node>(_graph.Nodes);
            dataGridView1.DataSource = source;
            dataGridView1.AutoGenerateColumns = true;

        }

        #region [EVENTS]

        #region [botones]
        private void btnNew_Click(object sender, EventArgs e)
        {
            _graph.Add();
            _lsTiles.Add(new Tile { Node = _graph.Last() });
            BindingList<Node> source = new BindingList<Node>(_graph.Nodes);
            dataGridView1.DataSource = source;
            LoadEdges();

            dataGridView1.Enabled = true;
            btnPaint.Enabled = true;
            btnExport.Enabled = true;
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            btnNew.Enabled = false;
            btnEdit.Enabled = false;
            dataGridView1.Enabled = false;
            btnSave.Enabled = true;
            btnCancel.Enabled = true;
            btnExport.Enabled = false;
            btnPaint.Enabled = false;
            EnableEdges(true);
            SelectNode((int)dataGridView1.SelectedRows[0].Cells["Index"].Value);
        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            btnNew.Enabled = true;
            btnEdit.Enabled = true;
            dataGridView1.Enabled = true;
            btnSave.Enabled = false;
            btnCancel.Enabled = false;
            btnExport.Enabled = true;
            btnPaint.Enabled = true;
            EnableEdges(false);
            lblSelectedNodeName.Text = "#####";
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            //var selectedNode = _graph[(int)dataGridView1.SelectedRows[0].Cells["Index"].Value];

            //if (ddlTop.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.Top, _graph[(int)ddlTop.SelectedValue]);
            //    if (ddlLeftTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlTop.SelectedValue].AddEdge(Edges.LeftBot, _graph[(int)ddlLeftTop.SelectedValue]);
            //    }
            //    if (ddlRightTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlTop.SelectedValue].AddEdge(Edges.RightBot, _graph[(int)ddlRightTop.SelectedValue]);
            //    }
            //}
            //else
            //{
            //    selectedNode[ Edges.Top] = null;
            //}
            //if (ddlRightTop.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.RightTop, _graph[(int)ddlRightTop.SelectedValue]);
            //    if (ddlTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlRightTop.SelectedValue].AddEdge(Edges.LeftTop, _graph[(int)ddlTop.SelectedValue]);
            //    }
            //    if (ddlRightBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlRightTop.SelectedValue].AddEdge(Edges.Bot, _graph[(int)ddlRightBot.SelectedValue]);
            //    }
            //}
            //else
            //{
            //    selectedNode[Edges.RightTop] = null;
            //}
            //if (ddlRightBot.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.RightBot, _graph[(int)ddlRightBot.SelectedValue]);
            //    if (ddlRightTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlRightBot.SelectedValue].AddEdge(Edges.Top, _graph[(int)ddlRightTop.SelectedValue]);
            //    }
            //    if (ddlBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlRightBot.SelectedValue].AddEdge(Edges.LeftBot, _graph[(int)ddlBot.SelectedValue]);
            //    }
            //}
            //if (ddlBot.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.Bot, _graph[(int)ddlBot.SelectedValue]);
            //    if (ddlRightBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlBot.SelectedValue].AddEdge(Edges.RightTop, _graph[(int)ddlRightBot.SelectedValue]);
            //    }
            //    if (ddlLeftBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlBot.SelectedValue].AddEdge(Edges.LeftTop, _graph[(int)ddlLeftBot.SelectedValue]);
            //    }
            //}
            //if (ddlLeftBot.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.LeftBot, _graph[(int)ddlLeftBot.SelectedValue]);
            //    if (ddlBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlLeftBot.SelectedValue].AddEdge(Edges.RightBot, _graph[(int)ddlBot.SelectedValue]);
            //    }
            //    if (ddlLeftTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlLeftBot.SelectedValue].AddEdge(Edges.Top, _graph[(int)ddlLeftTop.SelectedValue]);
            //    }
            //}
            //if (ddlLeftTop.SelectedIndex != -1)
            //{
            //    selectedNode.AddEdge(Edges.LeftTop, _graph[(int)ddlLeftTop.SelectedValue]);
            //    if (ddlLeftBot.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlLeftTop.SelectedValue].AddEdge(Edges.Bot, _graph[(int)ddlLeftBot.SelectedValue]);
            //    }
            //    if (ddlTop.SelectedIndex != -1)
            //    {
            //        _graph[(int)ddlLeftTop.SelectedValue].AddEdge(Edges.RightTop, _graph[(int)ddlTop.SelectedValue]);
            //    }
            //}



            //BindingList<Node> source = new BindingList<Node>(_graph.Nodes);
            //dataGridView1.DataSource = source;
            //btnNew.Enabled = true;
            //btnEdit.Enabled = true;
            //dataGridView1.Enabled = true;
            //btnSave.Enabled = false;
            //btnCancel.Enabled = false;
            //btnExport.Enabled = true;
            //btnPaint.Enabled = true;
            //EnableEdges(false);
            //lblSelectedNodeName.Text = "#####";
            //LoadEdges();
        }

        private void btnPaint_Click(object sender, EventArgs e)
        {
            var gruesoBorde = 5;
            var lados = 6;
            var radio = 50;

            BuildTilesFromNodes(gruesoBorde, lados, radio);

            foreach (var tile in _lsTiles)
            {
                tile.BorderThickness = gruesoBorde;
                tile.Sides = lados;
                tile.Radius = radio;
            }


            semiCanvas1.LstMapa = _lsTiles;

            semiCanvas1.Refresh();
        }

        private void btnExport_Click(object sender, EventArgs e)
        {
            System.Xml.Serialization.XmlSerializer writer =
                new System.Xml.Serialization.XmlSerializer(typeof(List<Node>));

            System.IO.StreamWriter file = new System.IO.StreamWriter(
                @"c:\SerializationOverview.xml");
            writer.Serialize(file, _graph.Nodes);
            file.Close();
            
            StringWriter sw = new StringWriter();
            writer.Serialize(sw, _graph.Nodes);

            Debug.Write(sw.ToString());
            txtConsole.Text = sw.ToString();
        }

        private void btnValidate_Click(object sender, EventArgs e)
        {
            txtConsole.Text += Environment.NewLine + (_graph.IsValid() ? "IS VALID!" : _graph.Errors);
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            _graph.StringBuilderErrors.Clear();
            txtConsole.Text = string.Empty;
        }

        private void button1_Click(object sender, EventArgs e)
        {

            _graph.AddNodeMysterious();
            _lsTiles.Add(new Tile { Node = _graph.Last() });
            BindingList<Node> source = new BindingList<Node>(_graph.Nodes);
            dataGridView1.DataSource = source;
            LoadEdges();

            dataGridView1.Enabled = true;
            btnPaint.Enabled = true;
            btnExport.Enabled = true;
        }
        #endregion

        #region [combos]
        private void ddlEdge1_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[1] = (int?)ddlTop.SelectedIndex != -1 ? (int?)ddlTop.SelectedIndex : null;

        }

        private void ddlEdge2_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[2] = (int?)ddlRightTop.SelectedIndex != -1 ? (int?)ddlRightTop.SelectedIndex : null;

        }

        private void ddlEdge3_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[3] = (int?)ddlRightBot.SelectedIndex != -1 ? (int?)ddlRightBot.SelectedIndex : null;

        }

        private void ddlEdge4_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[4] = (int?)ddlBot.SelectedIndex != -1 ? (int?)ddlBot.SelectedIndex : null;

        }

        private void ddlEdge5_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[5] = (int?)ddlLeftBot.SelectedIndex != -1 ? (int?)ddlLeftBot.SelectedIndex : null;

        }

        private void ddlEdge6_SelectedIndexChanged(object sender, EventArgs e)
        {
            _selectedNodes[6] = (int?)ddlLeftTop.SelectedIndex != -1 ? (int?)ddlLeftTop.SelectedIndex : null;

        }
        #endregion

        private void dataGridView1_SelectionChanged(object sender, EventArgs e)
        {
            if (dataGridView1.SelectedRows.Count > 0)
            {
                SelectNode((int)dataGridView1.SelectedRows[0].Cells["Index"].Value);
                btnEdit.Enabled = true;
            }
        }

        private void Main_Load(object sender, EventArgs e)
        {
            dataGridView1.Enabled = true;
            btnNew.Enabled = true;
            btnEdit.Enabled = false;
            btnCancel.Enabled = false;
            btnSave.Enabled = false;
            btnPaint.Enabled = false;
            btnExport.Enabled = false;
            EnableEdges(false);
        }

        #endregion


        #region [METHODS]
        private void LoadEdges()
        {
            ddlTop.DataSource = BuildBindingList(_graph.Nodes);
            ddlTop.DisplayMember = "Name";
            ddlTop.ValueMember = "Index";
            ddlTop.SelectedIndex = -1;

            ddlRightTop.DataSource = BuildBindingList(_graph.Nodes);
            ddlRightTop.DisplayMember = "Name";
            ddlRightTop.ValueMember = "Index";
            ddlRightTop.SelectedIndex = -1;

            ddlRightBot.DataSource = BuildBindingList(_graph.Nodes);
            ddlRightBot.DisplayMember = "Name";
            ddlRightBot.ValueMember = "Index";
            ddlRightBot.SelectedIndex = -1;

            ddlBot.DataSource = BuildBindingList(_graph.Nodes);
            ddlBot.DisplayMember = "Name";
            ddlBot.ValueMember = "Index";
            ddlBot.SelectedIndex = -1;

            ddlLeftBot.DataSource = BuildBindingList(_graph.Nodes);
            ddlLeftBot.DisplayMember = "Name";
            ddlLeftBot.ValueMember = "Index";
            ddlLeftBot.SelectedIndex = -1;

            ddlLeftTop.DataSource = BuildBindingList(_graph.Nodes);
            ddlLeftTop.DisplayMember = "Name";
            ddlLeftTop.ValueMember = "Index";
            ddlLeftTop.SelectedIndex = -1;
        }

        private BindingList<Node> BuildBindingList(List<Node> list)
        {
            List<Node> aux = new List<Node>(list);
            aux.Add(new Node() { Index = -1, Name = "" });
            foreach (var selectedNode in _selectedNodes)
            {
                if (selectedNode.HasValue)
                {
                    aux.Remove(aux.FirstOrDefault(node => node.Index == selectedNode));
                }
            }
            return new BindingList<Node>(aux);
        }

        private void EnableEdges(bool en)
        {
            ddlTop.Enabled = en;
            ddlRightTop.Enabled = en;
            ddlRightBot.Enabled = en;
            ddlBot.Enabled = en;
            ddlLeftBot.Enabled = en;
            ddlLeftTop.Enabled = en;
        }

        private void ClearEdgesSelection()
        {
            ddlTop.SelectedIndex = -1;
            ddlRightTop.SelectedIndex = -1;
            ddlRightBot.SelectedIndex = -1;
            ddlBot.SelectedIndex = -1;
            ddlLeftBot.SelectedIndex = -1;
            ddlLeftTop.SelectedIndex = -1;
            _selectedNodes = new int?[7];
        }

        private void SelectNode(int index)
        {
            ClearEdgesSelection();
            LoadEdges();
            if (index != -1)
            {
                Node selectedNode = _graph[index];

                var topNode = selectedNode[Edges.Top];
                if (topNode != null)
                    ddlTop.SelectedValue = topNode.Value;

                var rightTopNode = selectedNode[Edges.RightTop];
                if (rightTopNode != null)
                    ddlRightTop.SelectedValue = rightTopNode.Value;

                var rightBotNode = selectedNode[Edges.RightBot];
                if (rightBotNode != null)
                    ddlRightBot.SelectedValue = rightBotNode.Value;

                var botNode = selectedNode[Edges.Bot];
                if (botNode != null)
                    ddlBot.SelectedValue = botNode.Value;

                var leftBotNode = selectedNode[Edges.LeftBot];
                if (leftBotNode != null)
                    ddlLeftBot.SelectedValue = leftBotNode.Value;

                var leftTopNode = selectedNode[Edges.LeftTop];
                if (leftTopNode != null)
                    ddlLeftTop.SelectedValue = leftTopNode.Value;


                _selectedNodes[0] = index;
            }


            lblSelectedNodeName.Text = dataGridView1.SelectedRows[0].Cells["Name"].Value.ToString();
        }

        private void BuildTilesFromNodes(int gruesoBorde, int lados, int radio)
        {
            _lsTiles = new List<Tile>();
            var aux = new List<int?>();
            foreach (var node in _graph)
            {
                if (aux.Count == 0)
                {
                    var newTile = new Tile();
                    newTile.CenterX = 0;
                    newTile.CenterY = 0;
                    newTile.Node = node;
                    newTile.BorderThickness = gruesoBorde;
                    newTile.Radius = radio;
                    newTile.Sides = lados;
                    _lsTiles.Add(newTile);
                    aux.Add(node.Index);

                    if (node[Edges.Top].HasValue && !aux.Exists(i => i == node[Edges.Top]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6) * 2);
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.Top]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.RightTop].HasValue && !aux.Exists(i => i == node[Edges.RightTop]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX + radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6));
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.RightTop]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.RightBot].HasValue && !aux.Exists(i => i == node[Edges.RightBot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX + radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -1;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.RightBot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.Bot].HasValue && !aux.Exists(i => i == node[Edges.Bot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -2;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.Bot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.LeftBot].HasValue && !aux.Exists(i => i == node[Edges.LeftBot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX - radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -1;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.LeftBot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.LeftTop].HasValue && !aux.Exists(i => i == node[Edges.LeftTop]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX - radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6));
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.LeftTop]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }
                }


                else
                {
                    var newTile = _lsTiles.FirstOrDefault(tile => tile.Node.Index == node.Index);

                    if (node[Edges.Top].HasValue && !aux.Exists(i => i == node[Edges.Top]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6) * 2);
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.Top]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.RightTop].HasValue && !aux.Exists(i => i == node[Edges.RightTop]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX + radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6));
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.RightTop]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.RightBot].HasValue && !aux.Exists(i => i == node[Edges.RightBot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX + radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -1;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.RightBot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.Bot].HasValue && !aux.Exists(i => i == node[Edges.Bot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -2;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.Bot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.LeftBot].HasValue && !aux.Exists(i => i == node[Edges.LeftBot]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX - radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6)) * -1;
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.LeftBot]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }

                    if (node[Edges.LeftTop].HasValue && !aux.Exists(i => i == node[Edges.LeftTop]))
                    {
                        var newSideTile = new Tile();
                        newSideTile.CenterX = newTile.CenterX - radio * 1.5f;
                        newSideTile.CenterY = (float)(newTile.CenterY + radio * Math.Cos(Math.PI / 6));
                        newSideTile.Node = _graph.FirstOrDefault(node1 => node1.Index == node[Edges.LeftTop]);
                        newSideTile.BorderThickness = gruesoBorde;
                        newSideTile.Radius = radio;
                        newSideTile.Sides = lados;
                        aux.Add(newSideTile.Node.Index);
                        _lsTiles.Add(newSideTile);
                    }
                }



            }
        }
        #endregion

        

        






    }
}
